﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnliQ.Service.Contracts;

namespace UnliQ.Data.Repositories
{
    public class FakeQueueRepo : IQueueRepo
    {

        private List<EventDTO> _events = null;
        private List<EventDateDTO> _eventDates = null;
        private List<RecurringDTO> _recurring = null;
        private List<EventRecurringDTO> _eventRecurring = null;
        private List<EventDateSequenceDTO> _eventDateSequence = null;
        private List<EventSubscriberDTO> _eventSubscriber = null;
        private List<EventTriggerDTO> _eventTrigger = null;

        #region [Constructor(s)]
        public FakeQueueRepo()
        {
            _eventSubscriber = new List<EventSubscriberDTO>();

        }
        #endregion

        public void AddInitValues(IList<EventDTO> events, IList<EventDateDTO> eventDates, IList<RecurringDTO> recurring, IList<EventRecurringDTO> eventsRecurring, IList<EventDateSequenceDTO> eventDateSequence, IList<EventTriggerDTO> eventTrigger)
        {
            _events = events.ToList();
            _eventDates = eventDates.ToList();
            _recurring = recurring.ToList();
            _eventRecurring = eventsRecurring.ToList();
            _eventDateSequence = eventDateSequence.ToList();
            _eventTrigger = eventTrigger.ToList();
        }

        public EventDTO Get(int id)
        {
            return _events.Where(w => w.Id == id).FirstOrDefault();
        }

        public List<EventDTO> GetListActive()
        {
            var eventDateList = _eventDateSequence.Where(w => w.SubscribeStartDate <= DateTime.Now && w.SubscribeEndDate >= DateTime.Now)
                .Select(s => s.EventDateId).ToList();
            var eventList = _eventDates.Where(w => eventDateList.Contains(w.Id)).Select(s => s.EventId).ToList();

            return _events.Where(w => eventList.Contains(w.Id)).ToList();
        }

        public List<EventDTO> GetList()
        {
            return _events;
        }

        public int Insert(EventDTO value)
        {
            //Events
            if (value != null)
            {
                value.Id = this.GetEventId();
                value.CreatedDate = DateTime.Now;
                value.Active = true;

                //EventDates            
                if (value.EventDateDTO != null)
                {
                    value.EventDateDTO.Id = this.GetEventDateId();
                    value.EventDateDTO.EventRecurringId = value.EventDateDTO.EventRecurringDTO.Id;
                    value.EventDateDTO.EventId = value.Id;
                    value.EventDateDTO.CreatedDate = DateTime.Now;
                    value.EventDateDTO.Active = true;
                }

                //EventRecurring
                if (value.EventDateDTO.EventRecurringDTO != null)
                {
                    value.EventDateDTO.EventRecurringDTO.Id = this.GetEventRecurringId();
                    value.EventDateDTO.EventRecurringDTO.CreatedDate = DateTime.Now;
                    value.EventDateDTO.EventRecurringDTO.Active = true;
                }

                //EventTrigger            
                value.EventTriggerDTO = new EventTriggerDTO();
                value.EventTriggerDTO.Id = this.GetEventTriggerId();
                value.EventTriggerDTO.EventId = value.Id;
                value.EventTriggerDTO.UserId = value.PersonInCharge;

                _events.Add(value);
                _eventDates.Add(value.EventDateDTO);
                _eventRecurring.Add(value.EventDateDTO.EventRecurringDTO);
                _eventTrigger.Add(value.EventTriggerDTO);
            }

            return value.Id;
        }

        public void Update(EventDTO value)
        {
            var eventObj = _events.Find(w => w.Id == value.Id);
            var eventDateObj = _eventDates.Find(w => w.EventId == value.Id);
            var eventRecurringObj = _eventRecurring.Find(w => w.Id == value.EventDateDTO.EventRecurringId);

            if (eventObj != null)
            {
                eventObj.Name = value.Name;
                eventObj.Description = value.Description;
                eventObj.Room = value.Room;
                eventObj.PersonInCharge = value.PersonInCharge;
                eventObj.MaximumSubscriber = value.MaximumSubscriber;
                eventObj.TimeTriggered = value.TimeTriggered;
                eventObj.Private = value.Private;
                eventObj.UpdatedDate = DateTime.Now;
                eventObj.Active = value.Active;
            }

            if (eventDateObj != null)
            {
                eventDateObj.SubscribeStartDate = value.EventDateDTO.SubscribeStartDate;
                eventDateObj.SubscribeEndDate = value.EventDateDTO.SubscribeEndDate;
                eventDateObj.EventStartDate = value.EventDateDTO.EventStartDate;
                eventDateObj.EventEndDate = value.EventDateDTO.EventEndDate;
                eventDateObj.UpdatedDate = DateTime.Now;
                eventDateObj.Active = value.EventDateDTO.Active;
            }

            if (eventRecurringObj != null)
            {
                eventRecurringObj.RecurringId = value.EventDateDTO.EventRecurringDTO.RecurringId;
                eventRecurringObj.Value = value.EventDateDTO.EventRecurringDTO.Value;
                eventRecurringObj.UpdatedDate = DateTime.Now;
                eventRecurringObj.Active = value.EventDateDTO.EventRecurringDTO.Active;
            }
        }

        public void Delete(int id)
        {
            var eventObj = _events.Find(w => w.Id == id);
            var eventDateObj = _eventDates.Find(w => w.Id == eventObj.EventDateDTO.Id);
            var eventRecurringObj = _eventRecurring.Find(w => w.Id == eventDateObj.EventRecurringId);
            var eventTriggerObj = _eventTrigger.Find(w => w.EventId == id);

            if (eventObj != null)
            {
                _events.Remove(eventObj);
            }
            if (eventDateObj != null)
            {
                _eventDates.Remove(eventDateObj);
            }
            if (eventRecurringObj != null)
            {
                _eventRecurring.Remove(eventRecurringObj);
            }
            if (eventTriggerObj != null)
            {
                _eventTrigger.Remove(eventTriggerObj);
            }

        }

        public List<EventDTO> GetUserEvents(int userId)
        {
            var eventSubscriber = _eventSubscriber.Where(w => w.UserId == userId && w.Active).Select(s => s.EventDateSequenceId).ToList();

            var eventDateList = _eventDateSequence.Where(w => eventSubscriber.Contains(w.Id))
                .Select(s => s.EventDateId).ToList();

            var eventList = _eventDates.Where(w => eventDateList.Contains(w.Id)).Select(s => s.EventId).ToList();

            return _events.Where(w => eventList.Contains(w.Id)).ToList();
        }

        public List<int> GetUsersInEvent(string eventName = "", int eventId = 0)
        {
            var eventDateSequenceId = GetEventDateSequenceId(eventName, eventId);
            return _eventSubscriber.Where(w => w.EventDateSequenceId == eventDateSequenceId && w.Active).Select(s => s.Id).ToList();
        }

        public int AssignUserToQueue(int userId, string eventName = "", int eventId = 0)
        {
            var eventDateSequenceId = GetEventDateSequenceId(eventName, eventId);
            var eventSubscriber = new EventSubscriberDTO();
            if (!_eventSubscriber.Exists(e => e.UserId == userId && e.EventDateSequenceId == eventDateSequenceId && e.Active))
            {
                eventSubscriber.Id = this.GetEventSubscriberId();
                eventSubscriber.UserId = userId;
                eventSubscriber.EventDateSequenceId = eventDateSequenceId;
                eventSubscriber.CreatedDate = DateTime.Now;
                eventSubscriber.Active = true;

                _eventSubscriber.Add(eventSubscriber);
            }

            return _eventSubscriber.Count(w => w.EventDateSequenceId == eventDateSequenceId);
        }

        public void RemoveUserFromQueue(int userId, string eventName = "", int eventId = 0)
        {
            var eventDateSequenceId = GetEventDateSequenceId(eventName, eventId);

            var eventSubscription = _eventSubscriber.Find(f => f.UserId == userId && f.EventDateSequenceId == eventDateSequenceId);

            if (eventSubscription != null)
            {
                eventSubscription.Active = false;
            }
        }

        public int NextQueue(string eventName = "", int eventId = 0)
        {
            var eventDateSequenceId = GetEventDateSequenceId(eventName, eventId);
            var id = _eventSubscriber.Where(f => f.EventDateSequenceId == eventDateSequenceId && f.Active).OrderBy(o => o.Id).Select(s => s.Id).FirstOrDefault();

            var eventSubscription = _eventSubscriber.Find(f => f.Id == id);

            if (eventSubscription != null)
            {
                eventSubscription.Active = false;
            }

            return this.GetCurrentQueue(eventName, eventId);
        }

        private int GetEventDateSequenceId(string eventName, int eventId = 0)
        {
            
            if (!string.IsNullOrEmpty(eventName))
            {
                eventId = _events.Where(w => w.Name.ToLower() == eventName.ToLower()).Select(s => s.Id).SingleOrDefault();
            }
                       
            var eventDateId = _eventDates.Where(w => w.EventId == eventId).Select(s => s.Id).SingleOrDefault();
            var eventDateSequenceId = _eventDateSequence.Where(w => w.EventDateId == eventDateId).Select(s => s.Id).SingleOrDefault();
            return eventDateSequenceId;
        }

        public int GetCurrentQueue(string eventName = "", int eventId = 0)
        {
            var eventDateSequenceId = GetEventDateSequenceId(eventName, eventId);            

            return this.GetUsersInEvent(eventName, eventId).Count  - _eventSubscriber.Count(f => f.EventDateSequenceId == eventDateSequenceId && f.Active);
        }

        public List<EventDTO> GetUserTriggeredEvents(int userId)
        {
            var x = _eventTrigger.Where(w => w.UserId == userId).Select(s => s.EventId).ToList();

            return _events.Where(w => x.Contains(w.Id)).ToList();
        }

        private int GetEventId()
        {
            return _events.Max(m => m.Id) + 1;
        }

        private int GetEventDateId()
        {
            return _eventDates.Max(m => m.Id) + 1;
        }

        private int GetEventRecurringId()
        {
            return _eventRecurring.Max(m => m.Id) + 1;
        }

        private int GetRecurringId()
        {
            return _recurring.Max(m => m.Id) + 1;
        }

        private int GetEventSequenceId()
        {
            return _eventDateSequence.Max(m => m.Id) + 1;
        }

        private int GetEventSubscriberId()
        {
            return _eventSubscriber.Max(m => m.Id) + 1;
        }

        private int GetEventTriggerId()
        {
            return _eventTrigger.Max(m => m.Id) + 1;
        }
    }
}
